@file:OptIn(ExperimentalComposeUiApi::class)

package com.fanketly.musicdiary.test

import androidx.compose.foundation.*
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement.SpaceEvenly
import androidx.compose.material.Button
import androidx.compose.material.Switch
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.*
import androidx.compose.ui.focus.FocusRequester.Companion.Default
import androidx.compose.ui.graphics.Color.Companion.Black
import androidx.compose.ui.graphics.Color.Companion.Green
import androidx.compose.ui.graphics.Color.Companion.Red
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.fanketly.musicdiary.ui.theme.TestTheme
import com.fanketly.musicdiary.ui.theme.White

@Preview
@Composable
fun FocusPreview() {
    TestTheme {

        Column(
            Modifier
                .verticalScroll(rememberScrollState())
                .fillMaxSize()
                .background(White)
        ) {
//            CustomFocusOrderDemo()
//            CancelFocusMoveSample()
            Text(text = "MoveFocusSample")
            MoveFocusSample()
            Text(text = "CustomFocusExitSample")
            CustomFocusExitSample()
            Text(text = "CustomFocusEnterSample")
            CustomFocusEnterSample()
        }
    }
}

@Composable
fun CustomFocusEnterSample() {
    // 如果该行已获得焦点，则执行 moveFocus(Enter) 会将焦点移至 item2。
    val item2 = remember { FocusRequester() }
    var color by remember { mutableStateOf(Red) }
    Row(
        Modifier
            .height(200.dp)
            .background(color)
            .onFocusChanged { color = if (it.isFocused) Green else Red }
            .focusProperties { enter = { item2 } }
            .focusable()) {
        FocusBox()
        FocusBox(Modifier.focusRequester(item2))
        FocusBox()
    }
}


@Composable
fun CustomFocusExitSample() {
    // 如果 Row1 中的某个框已获得焦点，则执行 moveFocus(Exit) 会将焦点移至指定的下一项，而不是将焦点移至 row1。
    val nextItem = remember { FocusRequester() }
    var color by remember { mutableStateOf(Red) }
    var color2 by remember { mutableStateOf(Red) }
    Column {
        Row(
            Modifier
                .height(200.dp)
                .background(color)
                .onFocusChanged { color = if (it.isFocused) Green else Red }
                .focusProperties { exit = { nextItem } }//当exit时会焦点会到哪里
                .focusable()
        ) {
            FocusBox()
            FocusBox()
            FocusBox()
        }
        Row(
            Modifier
                .height(200.dp)
                .background(color2)
                .onFocusChanged { color2 = if (it.isFocused) Green else Red }
                .focusable()
        ) {
            FocusBox()
            FocusBox(Modifier.focusRequester(nextItem))//到这里
        }
    }
}

@Composable
fun MoveFocusSample() {
    val focusManager = LocalFocusManager.current
    Column {
        Row {
            FocusBox()
            FocusBox()
        }
        Row {
            FocusBox()
            FocusBox()
        }
        Button(onClick = { focusManager.moveFocus(FocusDirection.Right) }) { Text("Right") }
        Button(onClick = { focusManager.moveFocus(FocusDirection.Left) }) { Text("Left") }
        Button(onClick = { focusManager.moveFocus(FocusDirection.Up) }) { Text("Up") }
        Button(onClick = { focusManager.moveFocus(FocusDirection.Down) }) { Text("Down") }
        //在FocusManager.moveFocus中使用的方向指示您正在搜索作为当前焦点项的子项的下一个可焦点项
        Button(onClick = { focusManager.moveFocus(FocusDirection.Enter) }) { Text("Enter") }
        //FocusManager.moveFocus中使用的方向，表示您要将焦点移动到当前焦点项的父项
        Button(onClick = { focusManager.moveFocus(FocusDirection.Exit) }) { Text("Exit") }
    }
}

@Composable
fun CancelFocusMoveSample() {
    var color by remember { mutableStateOf(Black) }
    var color2 by remember { mutableStateOf(Black) }
    var color3 by remember { mutableStateOf(Black) }
    // 如果框 2 被聚焦，按向上键不会将焦点移到框 1，但按向下键会将焦点移到框 3。
    Column {
        // Box 1.
        Box(
            Modifier
                .size(100.dp)
                .background(color)
                .onFocusChanged { color = if (it.isFocused) Green else Black }
                .focusTarget()
        )
        // Box 2.
        Box(modifier = Modifier
            .size(100.dp)
            .background(color2)
            .onFocusChanged { color2 = if (it.isFocused) Green else Black }
            //取消了 focusRequester，当在 Modifier.focusProperties 中使用时意味着我们要阻止焦点搜索在指定方向上进行。
            .focusProperties { up = FocusRequester.Cancel }
            .focusTarget()
        )
        // Box 3.
        Box(
            Modifier
                .size(100.dp)
                .background(color3)
                .onFocusChanged { color3 = if (it.isFocused) Green else Black }
                .focusTarget())
    }
}


@Composable
fun CustomFocusOrderDemo() {
    Column {
        Row {
            Text(
                "使用箭头键将焦点从左到右向上移动。"
            )
        }
        Column(Modifier.fillMaxSize(), SpaceEvenly) {
            val (item1, item2, item3, item4) = remember { FocusRequester.createRefs() }
            var wrapAround by remember { mutableStateOf(false) }
            Row {
                Text("环绕焦点搜索")
                Switch(checked = wrapAround, onCheckedChange = { wrapAround = !wrapAround })
            }
            Row(Modifier.fillMaxWidth(), SpaceEvenly) {
                FocusableText(
                    text = "1",
                    modifier = Modifier
                        .focusRequester(item1)
                        .focusProperties {
                            left = if (wrapAround) item2 else Default
                            up = if (wrapAround) item3 else Default
                        }
                )
                FocusableText(
                    text = "2",
                    modifier = Modifier
                        .focusRequester(item2)
                        .focusProperties {
                            right = if (wrapAround) item1 else Default
                            up = if (wrapAround) item4 else Default
                        }
                )
            }
            Row(Modifier.fillMaxWidth(), SpaceEvenly) {
                FocusableText(
                    text = "3",
                    modifier = Modifier
                        .focusRequester(item3)
                        .focusProperties {
                            left = if (wrapAround) item4 else Default
                            down = if (wrapAround) item1 else Default
                        }
                )
                FocusableText(
                    text = "4",
                    modifier = Modifier
                        .focusRequester(item4)
                        .focusProperties {
                            right = if (wrapAround) item3 else Default
                            down = if (wrapAround) item2 else Default
                        }
                )
            }
            DisposableEffect(Unit) {
                item1.requestFocus()
                onDispose { }
            }
        }
    }
}

@Composable
fun FocusBox(modifier: Modifier = Modifier) {
    var color by remember { mutableStateOf(Black) }
    Box(
        modifier
            .size(100.dp)
            .background(color)
            .onFocusChanged { color = if (it.isFocused) Green else Black }
            .focusable())
}

@Composable
private fun FocusableText(text: String, modifier: Modifier = Modifier) {
    var color by remember { mutableStateOf(Black) }
    val focusRequester = remember { FocusRequester() }
    Text(
        modifier = modifier
            .border(width = 1.dp, color = Black)
            .requiredWidth(50.dp)
            .focusRequester(focusRequester)
            .onFocusChanged { color = if (it.isFocused) Green else Black }
            .focusTarget()
            .pointerInput(Unit) { detectTapGestures { focusRequester.requestFocus() } },
        text = text,
        fontSize = 40.sp,
        textAlign = TextAlign.Center,
        color = color
    )
}
